using System;
using System.IO;
namespace ICSharpCode.SharpZipLib.Zip
{
	public class ZipEntry
	{
		[Flags]
		private enum Known : byte
		{
			None = 0,
			Size = 1,
			CompressedSize = 2,
			Crc = 4,
			Time = 8,
			ExternalAttributes = 16
		}
		internal int AESKeySize;
		private ZipEntry.Known _known;
		private int _externalFileAttributes;
		private ushort _versionMadeBy;
		private readonly string _name;
		private ulong _size;
		private ulong _compressedSize;
		private readonly ushort _versionToExtract;
		private uint _crc;
		private uint _dosTime;
		private CompressionMethod _method;
		private byte[] _extra;
		private string _comment;
		private int _flags;
		private long _zipFileIndex;
		private long _offset;
		private bool _forceZip64;
		public bool HasCrc
		{
			get
			{
				return (byte)(this._known & ZipEntry.Known.Crc) != 0;
			}
		}
		public bool IsCrypted
		{
			get
			{
				return (this._flags & 1) != 0;
			}
			set
			{
				if (value)
				{
					this._flags |= 1;
				}
				else
				{
					this._flags &= -2;
				}
			}
		}
		public bool IsUnicodeText
		{
			get
			{
				return (this._flags & 2048) != 0;
			}
			set
			{
				if (value)
				{
					this._flags |= 2048;
				}
				else
				{
					this._flags &= -2049;
				}
			}
		}
		internal byte CryptoCheckValue
		{
			get;
			set;
		}
		public int Flags
		{
			get
			{
				return this._flags;
			}
			set
			{
				this._flags = value;
			}
		}
		public long ZipFileIndex
		{
			get
			{
				return this._zipFileIndex;
			}
			set
			{
				this._zipFileIndex = value;
			}
		}
		public long Offset
		{
			get
			{
				return this._offset;
			}
			set
			{
				this._offset = value;
			}
		}
		public int ExternalFileAttributes
		{
			get
			{
				int result;
				if ((byte)(this._known & ZipEntry.Known.ExternalAttributes) == 0)
				{
					result = -1;
				}
				else
				{
					result = this._externalFileAttributes;
				}
				return result;
			}
			set
			{
				this._externalFileAttributes = value;
				this._known |= ZipEntry.Known.ExternalAttributes;
			}
		}
		public int VersionMadeBy
		{
			get
			{
				return (int)(this._versionMadeBy & 255);
			}
		}
		public bool IsDOSEntry
		{
			get
			{
				return this.HostSystem == 0 || this.HostSystem == 10;
			}
		}
		public int HostSystem
		{
			get
			{
				return this._versionMadeBy >> 8 & 255;
			}
			set
			{
				this._versionMadeBy &= 255;
				this._versionMadeBy |= (ushort)((value & 255) << 8);
			}
		}
		public int Version
		{
			get
			{
				int result;
				if (this._versionToExtract != 0)
				{
					result = (int)this._versionToExtract;
				}
				else
				{
					int num = 10;
					if (this.AESKeySize > 0)
					{
						num = 51;
					}
					else
					{
						if (this.CentralHeaderRequiresZip64)
						{
							num = 45;
						}
						else
						{
							if (CompressionMethod.Deflated == this._method)
							{
								num = 20;
							}
							else
							{
								if (this.IsDirectory)
								{
									num = 20;
								}
								else
								{
									if (this.IsCrypted)
									{
										num = 20;
									}
									else
									{
										if (this.HasDosAttributes(8))
										{
											num = 11;
										}
									}
								}
							}
						}
					}
					result = num;
				}
				return result;
			}
		}
		public bool CanDecompress
		{
			get
			{
				return this.Version <= 51 && (this.Version == 10 || this.Version == 11 || this.Version == 20 || this.Version == 45 || this.Version == 51) && this.IsCompressionMethodSupported();
			}
		}
		public bool LocalHeaderRequiresZip64
		{
			get
			{
				bool result;
				if (!(result = this._forceZip64))
				{
					ulong num = this._compressedSize;
					if (this._versionToExtract == 0 && this.IsCrypted)
					{
						num += 12uL;
					}
					result = ((this._size >= (ulong)-1 || num >= (ulong)-1) && (this._versionToExtract == 0 || this._versionToExtract >= 45));
				}
				return result;
			}
		}
		public bool CentralHeaderRequiresZip64
		{
			get
			{
				return this.LocalHeaderRequiresZip64 || this._offset >= (long)((ulong)-1);
			}
		}
		public long DosTime
		{
			get
			{
				long result;
				if ((byte)(this._known & ZipEntry.Known.Time) == 0)
				{
					result = 0L;
				}
				else
				{
					result = (long)((ulong)this._dosTime);
				}
				return result;
			}
			set
			{
				this._dosTime = (uint)value;
				this._known |= ZipEntry.Known.Time;
			}
		}
		public DateTime DateTime
		{
			get
			{
				uint num = Math.Min(59u, 2u * (this._dosTime & 31u));
				uint num2 = Math.Min(59u, this._dosTime >> 5 & 63u);
				uint num3 = Math.Min(23u, this._dosTime >> 11 & 31u);
				uint num4 = Math.Max(1u, Math.Min(12u, this._dosTime >> 21 & 15u));
				uint num5 = (this._dosTime >> 25 & 127u) + 1980u;
				int num6 = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)num5, (int)num4), (int)(this._dosTime >> 16 & 31u)));
				return new DateTime((int)num5, (int)num4, num6, (int)num3, (int)num2, (int)num);
			}
			set
			{
				uint num = (uint)value.get_Year();
				uint num2 = (uint)value.get_Month();
				uint num3 = (uint)value.get_Day();
				uint num4 = (uint)value.get_Hour();
				uint num5 = (uint)value.get_Minute();
				uint num6 = (uint)value.get_Second();
				if (num < 1980u)
				{
					num = 1980u;
					num2 = 1u;
					num3 = 1u;
					num4 = 0u;
					num5 = 0u;
					num6 = 0u;
				}
				else
				{
					if (num > 2107u)
					{
						num = 2107u;
						num2 = 12u;
						num3 = 31u;
						num4 = 23u;
						num5 = 59u;
						num6 = 59u;
					}
				}
				this.DosTime = (long)((ulong)((num - 1980u & 127u) << 25 | num2 << 21 | num3 << 16 | num4 << 11 | num5 << 5 | num6 >> 1));
			}
		}
		public string Name
		{
			get
			{
				return this._name;
			}
		}
		public long Size
		{
			get
			{
				return (long)(((byte)(this._known & ZipEntry.Known.Size) != 0) ? this._size : 18446744073709551615uL);
			}
			set
			{
				this._size = (ulong)value;
				this._known |= ZipEntry.Known.Size;
			}
		}
		public long CompressedSize
		{
			get
			{
				return (long)(((byte)(this._known & ZipEntry.Known.CompressedSize) != 0) ? this._compressedSize : 18446744073709551615uL);
			}
			set
			{
				this._compressedSize = (ulong)value;
				this._known |= ZipEntry.Known.CompressedSize;
			}
		}
		public long Crc
		{
			get
			{
				return (long)(((byte)(this._known & ZipEntry.Known.Crc) != 0) ? ((ulong)this._crc & (ulong)-1) : 18446744073709551615uL);
			}
			set
			{
				this._crc = (uint)value;
				this._known |= ZipEntry.Known.Crc;
			}
		}
		public CompressionMethod CompressionMethod
		{
			get
			{
				return this._method;
			}
			set
			{
				if (!ZipEntry.IsCompressionMethodSupported(value))
				{
					throw new NotSupportedException("Compression method not supported");
				}
				this._method = value;
			}
		}
		internal CompressionMethod CompressionMethodForHeader
		{
			get
			{
				return (this.AESKeySize > 0) ? CompressionMethod.WinZipAES : this._method;
			}
		}
		public byte[] ExtraData
		{
			get
			{
				return this._extra;
			}
			set
			{
				if (value == null)
				{
					this._extra = null;
				}
				else
				{
					if (value.Length > 65535)
					{
						throw new ArgumentOutOfRangeException("value");
					}
					this._extra = new byte[value.Length];
					Array.Copy(value, 0, this._extra, 0, value.Length);
				}
			}
		}
		internal int AESSaltLen
		{
			get
			{
				return this.AESKeySize / 16;
			}
		}
		internal int AESOverheadSize
		{
			get
			{
				return 12 + this.AESSaltLen;
			}
		}
		public string Comment
		{
			get
			{
				return this._comment;
			}
			set
			{
				if (value != null && value.get_Length() > 65535)
				{
					throw new ArgumentOutOfRangeException("value", "cannot exceed 65535");
				}
				this._comment = value;
			}
		}
		public bool IsDirectory
		{
			get
			{
				int length = this._name.get_Length();
				int arg_41_0;
				if (length > 0)
				{
					if (this._name.get_Chars(length - 1) == '/' || this._name.get_Chars(length - 1) == '\\')
					{
						arg_41_0 = 1;
						return arg_41_0 != 0;
					}
				}
				arg_41_0 = (this.HasDosAttributes(16) ? 1 : 0);
				return arg_41_0 != 0;
			}
		}
		public bool IsFile
		{
			get
			{
				return !this.IsDirectory && !this.HasDosAttributes(8);
			}
		}
		public ZipEntry(string name) : this(name, 0, 51, CompressionMethod.Deflated)
		{
		}
		internal ZipEntry(string name, int versionRequiredToExtract) : this(name, versionRequiredToExtract, 51, CompressionMethod.Deflated)
		{
		}
		internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo, CompressionMethod method)
		{
			this._externalFileAttributes = -1;
			this._method = CompressionMethod.Deflated;
			this._zipFileIndex = -1L;
			base..ctor();
			if (name == null)
			{
				throw new ArgumentNullException("name");
			}
			if (name.get_Length() > 65535)
			{
				throw new ArgumentException("Name is too long", "name");
			}
			if (versionRequiredToExtract != 0 && versionRequiredToExtract < 10)
			{
				throw new ArgumentOutOfRangeException("versionRequiredToExtract");
			}
			this.DateTime = DateTime.get_Now();
			this._name = name;
			this._versionMadeBy = (ushort)madeByInfo;
			this._versionToExtract = (ushort)versionRequiredToExtract;
			this._method = method;
		}
		[Obsolete("Use Clone instead")]
		public ZipEntry(ZipEntry entry)
		{
			this._externalFileAttributes = -1;
			this._method = CompressionMethod.Deflated;
			this._zipFileIndex = -1L;
			base..ctor();
			if (entry == null)
			{
				throw new ArgumentNullException("entry");
			}
			this._known = entry._known;
			this._name = entry._name;
			this._size = entry._size;
			this._compressedSize = entry._compressedSize;
			this._crc = entry._crc;
			this._dosTime = entry._dosTime;
			this._method = entry._method;
			this._comment = entry._comment;
			this._versionToExtract = entry._versionToExtract;
			this._versionMadeBy = entry._versionMadeBy;
			this._externalFileAttributes = entry._externalFileAttributes;
			this._flags = entry._flags;
			this._zipFileIndex = entry._zipFileIndex;
			this._offset = entry._offset;
			this._forceZip64 = entry._forceZip64;
			if (entry._extra != null)
			{
				this._extra = new byte[entry._extra.Length];
				Array.Copy(entry._extra, 0, this._extra, 0, entry._extra.Length);
			}
		}
		private bool HasDosAttributes(int attributes)
		{
			bool result = false;
			if ((byte)(this._known & ZipEntry.Known.ExternalAttributes) != 0)
			{
				bool arg_36_0;
				if (this.HostSystem != 0)
				{
					if (this.HostSystem != 10)
					{
						arg_36_0 = true;
						goto IL_36;
					}
				}
				arg_36_0 = ((this.ExternalFileAttributes & attributes) != attributes);
				IL_36:
				if (!arg_36_0)
				{
					result = true;
				}
			}
			return result;
		}
		public void ForceZip64()
		{
			this._forceZip64 = true;
		}
		public bool IsZip64Forced()
		{
			return this._forceZip64;
		}
		internal void ProcessExtraData(bool localHeader)
		{
			ZipExtraData zipExtraData = new ZipExtraData(this._extra);
			if (zipExtraData.Find(1))
			{
				this._forceZip64 = true;
				if (zipExtraData.ValueLength < 4)
				{
					throw new ZipException("Extra data extended Zip64 information length is invalid");
				}
				if (localHeader || this._size == (ulong)-1)
				{
					this._size = (ulong)zipExtraData.ReadLong();
				}
				if (localHeader || this._compressedSize == (ulong)-1)
				{
					this._compressedSize = (ulong)zipExtraData.ReadLong();
				}
				if (!localHeader && this._offset == (long)((ulong)-1))
				{
					this._offset = zipExtraData.ReadLong();
				}
			}
			else
			{
				if ((this._versionToExtract & 255) >= 45 && (this._size == (ulong)-1 || this._compressedSize == (ulong)-1))
				{
					throw new ZipException("Zip64 Extended information required but is missing.");
				}
			}
			if (zipExtraData.Find(10))
			{
				if (zipExtraData.ValueLength < 4)
				{
					throw new ZipException("NTFS Extra data invalid");
				}
				zipExtraData.ReadInt();
				while (zipExtraData.UnreadCount >= 4)
				{
					int num = zipExtraData.ReadShort();
					int num2 = zipExtraData.ReadShort();
					if (num != 1)
					{
						zipExtraData.Skip(num2);
					}
					else
					{
						if (num2 >= 24)
						{
							long num3 = zipExtraData.ReadLong();
							zipExtraData.ReadLong();
							zipExtraData.ReadLong();
							this.DateTime = DateTime.FromFileTime(num3);
							break;
						}
						break;
					}
				}
			}
			else
			{
				if (zipExtraData.Find(21589))
				{
					int valueLength = zipExtraData.ValueLength;
					int num4 = zipExtraData.ReadByte();
					if ((num4 & 1) != 0 && valueLength >= 5)
					{
						int num5 = zipExtraData.ReadInt();
						this.DateTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() + new TimeSpan(0, 0, 0, num5, 0)).ToLocalTime();
					}
				}
			}
			if (this._method == CompressionMethod.WinZipAES)
			{
				throw new ZipException("AES unsupported");
			}
		}
		public bool IsCompressionMethodSupported()
		{
			return ZipEntry.IsCompressionMethodSupported(this.CompressionMethod);
		}
		public object Clone()
		{
			ZipEntry zipEntry = (ZipEntry)base.MemberwiseClone();
			if (this._extra != null)
			{
				zipEntry._extra = new byte[this._extra.Length];
				Array.Copy(this._extra, 0, zipEntry._extra, 0, this._extra.Length);
			}
			return zipEntry;
		}
		public override string ToString()
		{
			return this._name;
		}
		public static bool IsCompressionMethodSupported(CompressionMethod method)
		{
			return method == CompressionMethod.Deflated || method == CompressionMethod.Stored;
		}
		public static string CleanName(string name)
		{
			string result;
			if (name == null)
			{
				result = string.Empty;
			}
			else
			{
				if (Path.IsPathRooted(name))
				{
					name = name.Substring(Path.GetPathRoot(name).get_Length());
				}
				name = name.Replace("\\", "/");
				while (name.get_Length() > 0 && name.get_Chars(0) == '/')
				{
					name = name.Remove(0, 1);
				}
				result = name;
			}
			return result;
		}
	}
}
